import os
import sys
import signal
import select
import pickle
import new
import traceback
import gobject
if __name__ == "__main__":
    Control = object
else:
    import pattern
    from pattern.circuit import Control
    from pattern.serialization import picklers



class entry(Control):

    def realize(self, event):
        child_from_parent, parent_to_child = os.pipe()
        parent_from_child, child_to_parent = os.pipe()
        pid = os.fork()
        if pid != 0:
            self.pid = pid
            self._to = os.fdopen(parent_to_child, "w")
            self._from = os.fdopen(parent_from_child, "r")
            self.to_stream = picklers.PicklerWithCode(self._to)
            self.from_watch = \
                gobject.io_add_watch(self._from, gobject.IO_IN, 
                                     self.data_from_child, event)
            os.close(child_from_parent)
            os.close(child_to_parent)
        else:
            os.close(parent_from_child)
            os.close(parent_to_child)
            if getattr(event.shape, 'method', 'fork') == 'fork+exec':
                self.exec_child_mainloop(child_to_parent, child_from_parent)
            else:
                self.child_mainloop(child_to_parent, child_from_parent)
            

    def child_mainloop(self, child_to_parent, child_from_parent):
        sys.stdout = open("/tmp/work", "r+")
        sys.stderr = sys.stdout
        sys.pout = os.fdopen(child_to_parent, "w")
        _from = os.fdopen(child_from_parent, "r")
        from_stream = pickle.Unpickler(_from)
        locals()["__builtins__"] = __builtins__
        try:
            try:
                print "--- Entering child ---"
                sys.stdout.flush()
                while 1:
                    from_stream.memo.clear()
                    codedef, args = from_stream.load()
                    try:
                        new.function(codedef, locals())(*args)
                    except KeyboardInterrupt:
                        raise
                    except:
                        traceback.print_exc()
                    sys.stdout.flush()
            except KeyboardInterrupt:
                pass
            except:
                print "FATAL ERROR IN SUBPROCESS"
                traceback.print_exc()
        finally:
            print "--- Exiting child ---"
            sys.stdout.flush()
            os._exit(0)
        
    def exec_child_mainloop(self, child_to_parent, child_from_parent):
        try:
            os.execl("/usr/bin/python", "python", __file__,
                     pattern.__path__[0],
                     str(child_to_parent), str(child_from_parent))
        except:
            print "FATAL ERROR IN SUBPROCESS: Exec failed."
            traceback.print_exc()
        os._exit(0)

    def incoming(self, event):
        op, data = event.data
        transferring = (op.func_code, data)
        self.to_stream.memo.clear()
        self.to_stream.dump(transferring)
        self._to.flush()

    def data_from_child(self, source, condition, event):
        bridge = self.acquireInterface(event, "from")
        p = select.poll()
        p.register(source, select.POLLIN)
        while p.poll(1):
            #data = os.read(source.fileno(), 1024)
            data = pickle.load(source)
            if bridge is not None:
                try:
                    bridge.push(data)
                except:
                    traceback.print_exc()
        return True

    def shutdown(self, event):
        os.kill(self.pid, signal.SIGINT)
        os.waitpid(self.pid, os.P_WAIT)
        gobject.source_remove(self.from_watch)        


if __name__ == "__main__":
    e, pattern_path, to_parent, from_parent = sys.argv
    import imp
    imp.load_package("pattern", pattern_path)
    entry().child_mainloop(int(to_parent), int(from_parent))
